import wx
import pyaudio
import struct
import math
import cProfile
import numpy as np
import wave
import sys
import OpenGL.platform.win32
import OpenGL.arrays.numpymodule

sys.path += ['.']

from project import Project
from projectframe import ProjectFrame
from audiothread import AudioThread
from waveformpanel import *

audio = pyaudio.PyAudio()

# The application window. It's MDI (like photoshop or most audio packages)
class MainWindow(wx.MDIParentFrame):
    def __init__(self):
        wx.MDIParentFrame.__init__(self, None, -1, "MDI Parent",size=(800,600))

        self.tools = {}

        filemenu = wx.Menu()
        m_new  = filemenu.Append(-1, "&New File")
        m_open = filemenu.Append(-1, "&Open File")
        m_save = filemenu.Append(-1, "&Save File")
        m_exit = filemenu.Append(-1, "E&xit")

        viewmenu = wx.Menu()
        m_spectrogram = viewmenu.Append(-1, "&Show Spectrogram")

        menubar = wx.MenuBar()
        menubar.Append(filemenu, "&File")
        menubar.Append(viewmenu, "&View")

        self.currentProject = []

        #toolbar = wx.MDIChildFrame(self, -1, "tools", size=(400, 64), style = wx.CAPTION | wx.FRAME_TOOL_WINDOW)
        self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL | wx.TB_FLAT)
        for t in AllTools:
            bitmap = wx.Image(t.icon, wx.BITMAP_TYPE_ANY, index=-1).ConvertToBitmap()
            tid = self.toolbar.AddLabelTool(-1, t.name, bitmap)
            self.tools[tid.GetId()] = t
        self.toolbar.Realize()
        self.toolbar.Show(True)

        self.SetMenuBar(menubar)
        self.Bind(wx.EVT_MENU, self.OnNewFile, id=m_new.GetId())
        self.Bind(wx.EVT_MENU, self.OnOpenFile, id=m_open.GetId())
        self.Bind(wx.EVT_MENU, self.OnSaveFile, id=m_save.GetId())
        self.Bind(wx.EVT_MENU, self.OnExit, id=m_exit.GetId())
        self.Bind(wx.EVT_MENU, self.OnToggleSpectrogram, id=m_spectrogram.GetId())
        self.toolbar.Bind(wx.EVT_TOOL, self.OnToolSelect)
        
    def MakeProjectWindow(self, sampleData, name = "Untitled"):
        proj = Project( sampleData )
        stream = audio.open(format = pyaudio.paFloat32, channels = len(sampleData), rate = 44100, output = True)

        # Start the audio thread and create the frame which will display the waveform
        thread = AudioThread(stream, proj)
        win = ProjectFrame(self, -1, name, proj)

        # Run the thread and show the window
        thread.start()
        win.Show(True)

        # Store them for simple communication between them
        proj.thread = thread
        proj.window = win
        self.currentProject = proj

    def OnToggleSpectrogram(self, evt):
        self.currentProject.spectrogram = not self.currentProject.spectrogram

    def OnToolSelect(self, evt):
        if self.currentProject:
            self.currentProject.currentTool = self.tools[evt.GetId()]
            self.currentProject.currentTool.Cache(self.currentProject.sample)

    def OnExit(self, evt):
        self.Close(True)

    def OnSaveFile(self, evt):
        dialog = wx.FileDialog(None, style=wx.SAVE)
        if dialog.ShowModal() == wx.ID_OK:
            wf = wave.open(dialog.GetPath(), 'w')
            nchannels = len(self.currentProject.sample)
            
            #todo: pack_into
            wf.setparams((nchannels, 2, 44100, len(self.currentProject.originalSample), "NONE", "NONE"))
            wf.writeframes("".join([struct.pack("h",s * 32768) for s in self.currentProject.GetInterleavedSample()]))
            wf.close()

    def OnNewFile(self, evt):
        #single channel 44100 hz all 0
        self.MakeProjectWindow( [ np.array([0 for i in range(44100)], dtype=float) ] )

    def OnOpenFile(self, evt):
        dialog = wx.FileDialog(None, style=wx.OPEN)
        if dialog.ShowModal() == wx.ID_OK:
            wf = wave.open(dialog.GetPath(), 'r')
            (nchannels, sampwidth, framerate, nframes, comptype, compname) = wf.getparams ()
            frames = wf.readframes (nframes * nchannels)
            
            # We can use unpack_from to make this array real fast
            samp = np.array(struct.unpack_from ("%dh" % nframes * nchannels, frames), dtype=float)

            # 16bit or 24bit wavs are in signed integer format. (-32767 to 32768)
            # 32bit wavs are floats (-1.0 to 1.0)
            if sampwidth < 4:
                samp /= 32768.0
            channels = []
            for i in range(nchannels):
                channels.append( samp[i::nchannels] )

            self.MakeProjectWindow(channels, dialog.GetFilename())
        else:
            return

def main():
    app = wx.App()
    frame = MainWindow()
    frame.Show()
    app.MainLoop()
    
if __name__=="__main__":
    # Profiling (shows information when you close the program)
    #cProfile.run('main()', "profile.txt")

    # Run normally
    main()
